﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using Color = System.Windows.Media.Color;

namespace FractalTest
{
    internal partial class MainWindowViewModel : ObservableObject
    {
        private string _title = "Fractal Test";
        public string Title
        {
            get => _title;
            set => SetProperty(ref _title, value);
        }
        WriteableBitmap? _bitmap;
        public WriteableBitmap? Bitmap
        {
            get => _bitmap;
            set => SetProperty(ref _bitmap, value);
        }
        public MainWindowViewModel()
        {
            InitBitmap();
        }
        int width = 1200;
        int height = 800;
        [ObservableProperty]
        double mouseX;
        [ObservableProperty]
        double mouseY;
        [ObservableProperty]
        private double pScale;
        [ObservableProperty]
        private double pX;
        [ObservableProperty]
        private double pY;
        [ObservableProperty]
        private double cycleTime;
        private void InitBitmap()
        {
            Bitmap = new WriteableBitmap(width, height, 72, 72, PixelFormats.Bgr24, null);
            Bitmap.Lock();
            Bitmap backBitmap = new Bitmap(width, height, Bitmap.BackBufferStride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, Bitmap.BackBuffer);

            Graphics graphics = Graphics.FromImage(backBitmap);
            graphics.Clear(System.Drawing.Color.White);//整张画布置为白色

            Bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
            Bitmap.Unlock();
            data = new int[width, height];
            palette = new Color[256];
            GeneratePalette(palette);

            PScale = 1;
            PX = 0;
            PY = 0;
            CycleTime = 0;
            CX = -0.5;
            CY = 0;
        }
        private void DrawTest()
        {
            unsafe
            {
                var bytes = (byte*)Bitmap.BackBuffer.ToPointer();
                Bitmap.Lock();

                //整张画布置为白色
                for (int i = Bitmap.BackBufferStride * Bitmap.PixelHeight - 1; i >= 0; i--)
                {
                    bytes[i] = 255;
                }

                //画一些随机的红点
                Random rand = new Random();
                for (int i = 0; i < 10000; i++)
                {
                    int x = rand.Next(width);
                    int y = rand.Next(height);
                    int array_start = y * Bitmap.BackBufferStride + x * 3;

                    bytes[array_start] = 0;
                    bytes[array_start + 1] = 0;
                    bytes[array_start + 2] = 255;
                }

                Bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
                Bitmap.Unlock();
            }
        }
        Stopwatch sw = new();
        [ObservableProperty]
        private double cX = -0.5;
        [ObservableProperty]
        private double cY = 0;
        [ObservableProperty]
        private int maxIterations = 255;
        [ObservableProperty]
        private double zoom = 2.0;

        public double originScale;
        int[,] data = new int[1200, 800];
        Color[] palette = new Color[256];
        public void DrawFractal()
        {
            unsafe
            {
                var bytes = (byte*)Bitmap.BackBuffer.ToPointer();
                Bitmap.Lock();
                sw.Restart();

                //整张画布置为白色
                //for (int i = Bitmap.BackBufferStride * Bitmap.PixelHeight - 1; i >= 0; i--)
                //{
                //    bytes[i] = 255;
                //}
                //var mandelbrot = new MandelbrotCalculator();

                Zoom = 2.0 / PScale;
                MaxIterations = 255;
                MandelbrotCalculator.Compute2(width, height, data, centerX: CX, centerY: CY, scale: Zoom, maxIterations: MaxIterations);

                // 可根据data数组着色WriteableBitmap
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {

                        int iter = data[x, height - y - 1];
                        int array_start = y * Bitmap.BackBufferStride + x * 3;

                        // 颜色映射：黑色为集合内，其他为渐变色
                        if (iter >= MaxIterations)
                        {
                            bytes[array_start] = 0;     // B
                            bytes[array_start + 1] = 0; // G
                            bytes[array_start + 2] = 0; // R
                        }
                        else
                        {
                            // 简单的色带映射，可自定义
                            byte color = (byte)(255 * iter / MaxIterations);
                            if (iter < 64)
                            {
                                bytes[array_start] = (byte)(255);         // B
                                bytes[array_start + 1] = (byte)(4 * color); // G
                                bytes[array_start + 2] = 0; // R
                            }
                            else if (iter < 128)
                            {
                                bytes[array_start] = (byte)(2 * 255 - 4 * color); // B
                                bytes[array_start + 1] = (byte)(255);         // G
                                bytes[array_start + 2] = 0; // R
                            }
                            else if (iter < 192)
                            {
                                bytes[array_start] = 0; // B
                                bytes[array_start + 1] = (byte)(255);         // G
                                bytes[array_start + 2] = (byte)(4 * color - 2 * 255); // R
                            }
                            else
                            {
                                bytes[array_start] = 0; // B  
                                bytes[array_start + 1] = (byte)(4 * 255 - 4 * color); // G  
                                bytes[array_start + 2] = (byte)(255); // R  
                            }

                            //bytes[array_start] = (byte)(color);         // B
                            //bytes[array_start + 1] = (byte)(255 - color); // G
                            //bytes[array_start + 2] = (byte)(128 + color / 2); // R
                        }

                        //bytes[array_start] = 0;
                        //bytes[array_start + 1] = 0;
                        //bytes[array_start + 2] = (byte)data[x, y];
                    }
                }

                sw.Stop();
                CycleTime = sw.ElapsedMilliseconds;
                //CycleTime = sw.ElapsedMilliseconds;
                Bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
                Bitmap.Unlock();
            }
        }
        //并行优化版本
        public void DrawFractal1()
        {
            unsafe
            {
                Bitmap.Lock();
                var bytes = (byte*)Bitmap.BackBuffer.ToPointer();
                int stride = Bitmap.BackBufferStride;

                sw.Restart();
                Zoom = 2.0 / PScale;
                MaxIterations = 255;
                MandelbrotCalculator.Compute2(width, height, data, centerX: CX, centerY: CY, scale: Zoom, maxIterations: MaxIterations);

                // 预生成色表

                Parallel.For(0, height, y =>
                {
                    int rowStart = y * stride;
                    int dataY = height - y - 1;
                    for (int x = 0; x < width; x++)
                    {
                        int iter = data[x, dataY];
                        int array_start = rowStart + x * 3;
                        var color = palette[iter];
                        bytes[array_start] = color.B;
                        bytes[array_start + 1] = color.G;
                        bytes[array_start + 2] = color.R;
                    }
                });

                sw.Stop();
                CycleTime = sw.ElapsedMilliseconds;
                Bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
                Bitmap.Unlock();
            }
        }
        // 生成色表方法（可自定义色带）
        private Color[] GeneratePalette(int maxIterations)
        {
            var palette = new Color[maxIterations + 1];
            for (int i = 0; i <= maxIterations; i++)
            {
                // 这里可自定义色带算法
                byte c = (byte)(255 * i / maxIterations);
                palette[i] = i == maxIterations
                    ? Color.FromRgb(0, 0, 0)
                    : Color.FromRgb(c, (byte)(255 - c), (byte)(128 + c / 2));

            }
            return palette;
        }
        // 生成色表方法（自定义色带）
        private void GeneratePalette(Color[] palette)
        {
            int maxIterations = 255;
            for (int i = 0; i < 64; i++)
            {
                palette[i] = Color.FromRgb(0, (byte)(4 * i), 255);
            }
            for (int i = 64; i < 128; i++)
            {
                palette[i] = Color.FromRgb(0, 255, (byte)(2 * 255 - 4 * i));
            }
            for (int i = 128; i < 192; i++)
            {
                palette[i] = Color.FromRgb((byte)(2 * 255 - 4 * i), 255, 0);
            }
            for (int i = 192; i < maxIterations; i++)
            {
                palette[i] = Color.FromRgb(255, (byte)(4 * 255 - 4 * i), 0);
            }
            palette[maxIterations] = Color.FromRgb(0, 0, 0);
        }
        [RelayCommand]
        private void Reset()
        {
            InitBitmap();
            DrawFractal();
        }
        [RelayCommand]
        private void Generate()
        {
            DrawFractal1();
        }
    }
}
